#ifndef _POLLMGR_H
#define _POLLMGR_H 

// based on Jeremy Stribling and Alex Pesterev's 6.824 lab project

#include <pthread.h>
#include <sys/select.h>
#include <vector>

#ifdef __linux__
#include <sys/epoll.h>
#endif

// TODO to use _SC_OPEN_MAX?
#define MAX_POLL_FDS 128

typedef enum {
	PM_NONE = 0x0,
	PM_RDONLY = 0x1,
	PM_WRONLY = 0x10,
	PM_RDWR = 0x11,
	PM_MASK = ~0x11,
} poll_flag;

class pollmgr {
	public:
		virtual bool watch_fd(int fd, poll_flag flag) = 0;
		virtual bool unwatch_fd(int fd, poll_flag flag) = 0;
		virtual bool is_watched(int fd, poll_flag flag) = 0;
		virtual void wait_ready(std::vector<int> &readable,
                std::vector<int> &writable) = 0;
		virtual ~pollmgr() {}
};

class SelectAIO : public pollmgr {
	public :

		SelectAIO();
		~SelectAIO();
		bool watch_fd(int fd, poll_flag flag);
		bool unwatch_fd(int fd, poll_flag flag);
		bool is_watched(int fd, poll_flag flag);
		void wait_ready(std::vector<int> &readable, std::vector<int> &writable);

	private:

		fd_set rfds_;
		fd_set wfds_;
		int highfds_;
		int pipefd_[2];

		pthread_mutex_t m_;

};

#ifdef __linux__ 
class EPollAIO : public pollmgr {
	public:
		EPollAIO();
		~EPollAIO();
		bool watch_fd(int fd, poll_flag flag);
		bool unwatch_fd(int fd, poll_flag flag);
		bool is_watched(int fd, poll_flag flag);
		void wait_ready(std::vector<int> &readable, std::vector<int> &writable);

	private:
		int pollfd_;
		struct epoll_event ready_[MAX_POLL_FDS];
		int fdstatus_[MAX_POLL_FDS];

};
#endif /* __linux */

#endif /* _POLL_MGR_H */

